package org.dant.ant.extension.net.processors;

import java.io.*;
import java.util.*;

import org.dant.apache.tools.ant.taskdefs.Execute;
import org.dant.ant.extension.types.Expect;
import org.dant.ant.extension.utils.StringUtils;
import org.dant.ant.extension.tasks.internal.RemoteResponse;
import org.dant.ant.extension.net.DefaultDispatcher;

public class CheckThread implements Runnable {

  protected Process process;

  protected List expectlist;
  protected RemoteResponse results;
  
  protected List expectFiles = new ArrayList();

  protected boolean succeed = true;
  protected File dir = null;

  protected Execute exe;
  protected String processKey;

  protected boolean blocking;

  protected ErrorChecker errchecker;
  protected OutputChecker outchecker;
  
  protected Thread errorThread;
  protected Thread outputThread;

  public CheckThread() {
    results = new RemoteResponse();
    errchecker = new ErrorChecker(this);
    outchecker = new OutputChecker(this);
  }

  public void setBlocking(boolean blocking) {
    this.blocking = blocking;
  }

  public void setProcessKey(String key) {
    this.processKey = key;
  }

  public void setExecute(Execute exe) {
    this.exe = exe;
  }

  public boolean isFinished() {
    return (errchecker.isFinished() && outchecker.isFinished());
  }

  public void setDir(File dir) {
    this.dir = dir;
  }

  public void shutdown() {
    if (errorThread.isAlive()) {
      System.out.println("Shuting down the std.err checker thread");
      errorThread.destroy();
    }
    if (outputThread.isAlive()) {
      System.out.println("Shuting down the std.out checker thread");
      outputThread.destroy();
    }
  }
  
  public void run() {
    try {
      check();
      join();
      notifyExe();
    } catch (Exception e){
      e.printStackTrace();
    }
  }

  public void join() throws InterruptedException {
    outputThread.join();
    errorThread.join();

    if (!errchecker.isFinished() || !outchecker.isFinished()) {
      System.out.println("The processing is succeed and it is finished now");
      if (!blocking) {
        System.out.println("And this process is not a blocking process, so we are going to destroy the process");
        DefaultDispatcher.getProcessRepository().remove(processKey, process);
      } else {
        System.out.println("And this process is a blocking process, ");
        System.out.println(" so you need to stop the process manually by <remotestop> task ");
        System.out.println(" or CTRL+C to stop all the processes lanunched by the daemon server");
      }
    }
  }

  private void setResults() {
    results.setSuccess(succeed);
    results.setStdErrBuffer(errchecker.getErrorBuffer());
    results.setStdOutBuffer(outchecker.getOutputBuffer());
  }
  
  protected void notifyExe() {
    setResults();
    synchronized(exe) {
      exe.notify();
    }
  }

  public boolean isSucceed() {
    return this.succeed;
  }

  public void setSucceed(boolean succeed) {
    this.succeed = succeed;
  }

  private void checkStdError(){
    errorThread = new Thread(errchecker);
    //    errorThread.setDaemon(true);
    errorThread.start();
  }

  private void checkStdOutput(){
    outputThread = new Thread(outchecker);
    //    outputThread.setDaemon(true);
    outputThread.start();
  }

  private void check() throws IOException {
    checkFiles();
    checkStdError();
    checkStdOutput();
  }

  private void checkFiles() {
    System.out.println("check files");
    for(Iterator iter=expectFiles.iterator(); iter.hasNext();) {
      File file = (File) iter.next();
      if (!file.exists()) {
        succeed = false;
        results.appendResult("Expected file: " + file + " is not exist");
        break;
      }
    }
  }

  public void setProcess(Process process) {
    this.process = process;
    setProcessInputStream(process.getInputStream());
    setProcessErrorStream(process.getErrorStream());
  }
  
  public void setProcessInputStream(InputStream is){
    outchecker.setProcessInputStream(is);
  }

  public void setProcessErrorStream(InputStream is){
    errchecker.setProcessErrorStream(is);
  }

  private void setupExpectStream() {
    for (Iterator iter=expectlist.iterator(); iter.hasNext();) {
      Expect expect =  (Expect) iter.next();
      File file = expect.getFile();
      if (file == null) {
        System.out.println("Expect Stream: " + expect.getText());
        if (expect.isErrStream()) {
          errchecker.addExpectStream(expect.getText());
        } else {
          outchecker.addExpectStream(expect.getText());
        }
      } else {
        String path = expect.getFile().toString();
        expectFiles.add(resolvePath(path));
        System.out.println(expectFiles.size() + " Expect Files:" + expect.getFile().toString());
      }
    }
  }
  
  public void setExpectList(List expectlist) {
    this.expectlist = expectlist;
    if (this.expectlist != null) 
      setupExpectStream();
    //    printExpectStream();
  }

  public void setResultsList(List resultsList) {
    if (resultsList != null)
      resultsList.add(results);
  }

  private File resolvePath(String path) {
    return new File(dir, path);
  }
}
